package com.example.springboot0507.basic.web;


import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.example.springboot0507.basic.constant.CommonConstants;
import lombok.experimental.UtilityClass;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.http.MediaType;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.imageio.ImageIO;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.awt.image.BufferedImage;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;

/**
 * Web工具类
 */
@Slf4j
@UtilityClass
public class WebUtils extends org.springframework.web.util.WebUtils {
    private final String BASIC_ = "Basic ";
    private final String UNKNOWN = "unknown";

    /**
     * 读取cookie
     *
     * @param name cookie name
     * @return cookie value
     */
    public String getCookieVal(String name) {
        HttpServletRequest request = WebUtils.getRequest();
        Assert.notNull(request, "request from RequestContextHolder is null");
        return getCookieVal(request, name);
    }

    /**
     * 读取cookie
     *
     * @param request HttpServletRequest
     * @param name    cookie name
     * @return cookie value
     */
    public String getCookieVal(HttpServletRequest request, String name) {
        Cookie cookie = getCookie(request, name);
        return cookie != null ? cookie.getValue() : null;
    }

    /**
     * 清除 某个指定的cookie
     *
     * @param response HttpServletResponse
     * @param key      cookie key
     */
    public void removeCookie(HttpServletResponse response, String key) {
        setCookie(response, key, null, 0);
    }

    /**
     * 设置cookie
     *
     * @param response        HttpServletResponse
     * @param name            cookie name
     * @param value           cookie value
     * @param maxAgeInSeconds maxage
     */
    public void setCookie(HttpServletResponse response, String name, String value, int maxAgeInSeconds) {
        Cookie cookie = new Cookie(name, value);
        cookie.setPath("/");
        cookie.setMaxAge(maxAgeInSeconds);
        cookie.setHttpOnly(true);
        response.addCookie(cookie);
    }

    /**
     * 获取 HttpServletRequest
     *
     * @return {HttpServletRequest}
     */
    public HttpServletRequest getRequest() {
        if(Objects.isNull(RequestContextHolder.getRequestAttributes())) return null;
        return ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
    }

    /**
     * 获取 HttpServletResponse
     *
     * @return {HttpServletResponse}
     */
    public HttpServletResponse getResponse() {
        return ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getResponse();
    }

    /**
     * 返回json
     *
     * @param response HttpServletResponse
     * @param result   结果对象
     */
    public void renderJson(HttpServletResponse response, Object result) {
        renderJson(response, result, MediaType.APPLICATION_JSON_UTF8_VALUE);
    }

    /**
     * 返回json
     *
     * @param response    HttpServletResponse
     * @param result      结果对象
     * @param contentType contentType
     */
    public void renderJson(HttpServletResponse response, Object result, String contentType) {
        response.setCharacterEncoding("UTF-8");
        response.setContentType(contentType);
        try (PrintWriter out = response.getWriter()) {
            out.append(JSONUtil.toJsonStr(result));
        } catch (IOException e) {
            log.error(e.getMessage(), e);
        }
    }

    /**
     * 发送Img
     *
     * @param image 图片
     * @param style 图片格式
     */
    public final void sendImage(BufferedImage image, String style) {
        try {
            ImageIO.write(image, style, getResponse().getOutputStream());
        } catch (IOException e) {
            log.info("sendImage is wrong :{}", e.getMessage(), e);
        }
    }

    /**
     * 获取ip
     *
     * @return {String}
     */
    public String getIP() {
        return getIP(WebUtils.getRequest());
    }

    /**
     * 获取ip
     *
     * @param request HttpServletRequest
     * @return {String}
     */
    public String getIP(HttpServletRequest request) {
        Assert.notNull(request, "HttpServletRequest is null");
        String ip = request.getHeader("X-Requested-For");
        if (StringUtils.isEmpty(ip) || UNKNOWN.equalsIgnoreCase(ip)) {
            ip = request.getHeader("X-Forwarded-For");
        }
        if (StringUtils.isEmpty(ip) || UNKNOWN.equalsIgnoreCase(ip)) {
            ip = request.getHeader("Proxy-Client-IP");
        }
        if (StringUtils.isEmpty(ip) || UNKNOWN.equalsIgnoreCase(ip)) {
            ip = request.getHeader("WL-Proxy-Client-IP");
        }
        if (StringUtils.isEmpty(ip) || UNKNOWN.equalsIgnoreCase(ip)) {
            ip = request.getHeader("HTTP_CLIENT_IP");
        }
        if (StringUtils.isEmpty(ip) || UNKNOWN.equalsIgnoreCase(ip)) {
            ip = request.getHeader("HTTP_X_FORWARDED_FOR");
        }
        if (StringUtils.isEmpty(ip) || UNKNOWN.equalsIgnoreCase(ip)) {
            ip = request.getRemoteAddr();
        }
        return StringUtils.isEmpty(ip) ? null : ip.split(",")[0];
    }

    /**
     * 获取客户端
     *
     * @return
     */
    public String getUserAgent() {
        HttpServletRequest request = WebUtils.getRequest();
        Assert.notNull(request, "HttpServletRequest is null");
        return request.getHeader("User-Agent");
    }

    /**
     * 获取JSON请求参数
     *
     * @return
     */
    public Map<String, Object> getRequestJsonParam() {
        Map<String, Object> mapParam = null;
        try {
            // 获取输入流
            BufferedReader streamReader = new BufferedReader(
                    new InputStreamReader(getRequest().getInputStream(), "UTF-8"));
            StringBuilder builder = new StringBuilder();
            String line = null;
            while ((line = streamReader.readLine()) != null) {
                builder.append(line);
            }
            log.info("method [getRequestJsonParam][builder]:{}", builder.toString());
            mapParam = JSONUtil.toBean(builder.toString(), Map.class);
        } catch (Exception e) {
            log.error("happen err : {}", e.getMessage(), e);
        }
        return mapParam;
    }




    /**
     * 构建分页参数
     * @return
     */
    public PageRequest buildPageRequest(Sort sort){
        HttpServletRequest request = getRequest();
        String pageStr = request.getParameter("page");
        if (StringUtils.isEmpty(pageStr)) {
            pageStr = request.getParameter("pageNum");
        }
        String sizeStr = request.getParameter("size");
        if (StringUtils.isEmpty(sizeStr)) {
            sizeStr = request.getParameter("pageSize");
        }
        int page = CommonConstants.PAGE_NO;
        int size = CommonConstants.PAGE_SIZE;
        if (StrUtil.isNotEmpty(pageStr)) {
            page = Integer.valueOf(pageStr);
        }
        if (StrUtil.isNotEmpty(sizeStr)) {
            size = Integer.valueOf(sizeStr);
        }
        return PageRequest.of(page-1, size, sort);
    }

    /**
     * 构建分页请求参数
     *
     * @return
     */
    public PageRequest buildPageRequest() {
        return buildPageRequest(initSort());
    }

    /**
     * 构建排序条件
     *
     * @return
     */
    private Sort initSort() {
        Map<String, Object> sortParams = getParametersStartingWith(getRequest(), "sort");
        List<Sort.Order> orders = new ArrayList<>();
        sortParams.forEach((key, value) -> {
            String[] params = key.split("_");
            String filedName = params[1];
            try {
                Sort.Direction direction = Sort.Direction.valueOf(params[2].toUpperCase());
                orders.add(new Sort.Order(direction, filedName));
            } catch (IllegalArgumentException e) {
                //do nothing
            }
        });

        if (orders.size() != 0) {
            return Sort.by(orders);
        } else {
            return Sort.by(Sort.Direction.DESC, "createTime");
        }

    }
}
